package com.flyco.modules.jddj.handle.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.flyco.common.constant.StockConstant;
import com.flyco.common.util.*;
import com.flyco.modules.jddj.controller.AESUtils;
import com.flyco.modules.jddj.handle.IJddjOrderHandle;
import com.flyco.modules.jddj.sdk.dto.WebRequestDTO;
import com.flyco.modules.jddj.sdk.util.SignUtils;
import com.flyco.modules.jddj.vo.OmsJddjOrderVO;
import com.flyco.modules.oms.entity.*;
import com.flyco.modules.oms.handle.IThirdOrderHandle;
import com.flyco.modules.oms.service.IOmsJddjOrderService;
import com.flyco.modules.oms.vo.OmsOrderPage;
import com.flyco.modules.stm.service.IStmOrderAdditionService;
import com.flyco.modules.stm.service.IStmOrderService;
import com.flyco.modules.stm.service.IStmStockService;
import com.flyco.modules.stm.vo.StmStockVO;
import com.flyco.modules.util.ApiUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class JddjOrderHandleImpl implements IJddjOrderHandle {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IThirdOrderHandle thirdOrderHandle;
    @Autowired
    private IStmOrderService stmOrderService;
    @Autowired
    private IStmStockService stmStockService;

    private static String format = "json";
    private static String v = "1.0";
    private static Integer pageSize = 50;
    private static String orderUrl = "https://openo2o.jd.com/djapi/order/es/query";
    private static String orderBillUrl = "https://openapi.jddj.com/djapi/bill/checkBill";
    private static String balanceBillUrl = "https://openapi.jddj.com/djapi/balance/getBalanceBillList";

    @Autowired
    private IOmsJddjOrderService omsJddjOrderService;
    @Autowired
    private IStmOrderAdditionService stmOrderAdditionService;

    @Override
    public String getJddjOrder() throws Exception{
        List<OmsJddjOrderVO> orderVOS = new ArrayList<>();
        //搜索的时间范围
        Date beginTime = DateUtil.offsetDay(new Date(), -7).toJdkDate();
        /*if (beginTime.before(DateUtil.beginOfMonth(new Date())) ) {
            beginTime = DateUtil.beginOfMonth(new Date());
        }*/
        Date now = new Date();

        getJddjOrderWithPage(DateUtil.format(beginTime, DatePattern.NORM_DATETIME_PATTERN),
                DateUtil.format(now, DatePattern.NORM_DATETIME_PATTERN), 1L,orderVOS);
        if (orderVOS.size() == 0) return "没有同步到京东到家订单";
        checkJddjOrderWithDb(orderVOS);
        if (orderVOS.size() == 0) return "该时段订单已同步完成，无需再次同步";

        //查询京东对账单
        List<OmsJddjBalanceBill> balanceBillList = new ArrayList<>();
        if (DateUtil.betweenMonth(beginTime, now, true) > 0) {
            getJddiBalanceBillList(DateUtil.format(beginTime, DatePattern.PURE_DATE_PATTERN),
                    DateUtil.format(DateUtil.endOfMonth(beginTime), DatePattern.PURE_DATE_PATTERN),1L,1,balanceBillList);
            getJddiBalanceBillList(DateUtil.format(DateUtil.beginOfMonth(now), DatePattern.PURE_DATE_PATTERN),
                    DateUtil.format(now, DatePattern.PURE_DATE_PATTERN),1L,1,balanceBillList);
        } else {
            getJddiBalanceBillList(DateUtil.format(beginTime, DatePattern.PURE_DATE_PATTERN),
                    DateUtil.format(now, DatePattern.PURE_DATE_PATTERN),1L,1,balanceBillList);
        }
        if(balanceBillList.isEmpty()){
            return "没有查询到订单计费明细";
        }
        //设置账单，移除没有计费明细的订单
        removeOrderIfNoBalanceBill(orderVOS,balanceBillList);
        if (orderVOS.size() == 0) return "该时段订单没有查询到订单计费明细";

        //根据京东订单号，查询订单计费明细
        /*List<OmsJddjOrderBill> jddjOrderBillList = getJddjOrderBillList(orderVOS.stream().map(OmsJddjOrderVO::getOrderId).collect(Collectors.toList()));
        if(jddjOrderBillList.isEmpty()){
            return "没有查询到订单计费明细";
        }
        //移除没有计费明细的订单
        removeOrderIfNoBill(orderVOS,jddjOrderBillList);
        if (orderVOS.size() == 0) return "该时段订单没有查询到订单计费明细";*/

        orderVOS.forEach(vo->{
            OmsJddjOrder omsJddjOrder = new OmsJddjOrder();
            vo.setId(generateOrderSn());
            vo.setCreateTime(vo.getOrderStartTime());
            BeanUtils.copyProperties(vo, omsJddjOrder);
            List<OmsJddjOrderInvoice> invoices = new ArrayList<>();
            List<OmsJddjOrderDiscount> discounts = new ArrayList<>();
            if (oConvertUtils.isNotEmpty(vo.getOrderInvoice())) {
                invoices.add(vo.getOrderInvoice());
            }
            if (oConvertUtils.isNotEmpty(vo.getDiscount())) {
                discounts.addAll(vo.getDiscount());
            }
            omsJddjOrderService.saveMain(omsJddjOrder, vo.getProduct(), invoices, discounts,vo.getBalanceBillList());
            convertStoreOrder(vo);
    });
        return "同步京东到家订单完成";
    }

    /**
     * 查询京东到家账单
     * 传入开始时间，结束时间
     * @return
     */
     void getJddiBalanceBillList(String startDate, String endDate, Long pageNum, Integer billType, List<OmsJddjBalanceBill> balanceBillList) throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("pageNum", pageNum);
        jsonObject.put("pageSize", 20);
        jsonObject.put("orderStartTime", startDate);
        jsonObject.put("orderEndTime", endDate);
        jsonObject.put("billType", billType);
        String timestamp = DateUtils.now();
        JSONObject resultObj = requestJddjHttp(balanceBillUrl, jsonObject.toJSONString(), timestamp);
        if (resultObj!=null) {
            if (Objects.equals("0", resultObj.getString("code"))) {

                String encryptData = resultObj.getString("encryptData");
                if(StrUtil.isBlank(encryptData)) {
                    throw new RuntimeException("encryptData为空");
                }
                String key = ApiUtil.getJddjAppSecret().substring(0, 16);
                String iv = ApiUtil.getJddjAppSecret().substring(16, 32);
                String data = AESUtils.decryptAES(encryptData, key, iv);
                JSONObject content = JSONObject.parseObject(data).getJSONObject("content");
                if (oConvertUtils.isEmpty(content) || oConvertUtils.isEmpty(content.getJSONObject("billList"))){
                    if(billType==1) {
                        billType = 2;
                        getJddiBalanceBillList(startDate, endDate, 1L, billType, balanceBillList);
                    }
                    return;
                }
                JSONObject billList = content.getJSONObject("billList");
                JSONArray jsonArray = billList.getJSONArray("result");
                List<OmsJddjBalanceBill> voList = JSONArray.parseArray(jsonArray.toJSONString(), OmsJddjBalanceBill.class);
                balanceBillList.addAll(voList);
                Integer pages = billList.getInteger("pages");
                if (pageNum < pages) {
                    getJddiBalanceBillList(startDate,endDate,pageNum + 1, billType,balanceBillList);
                }else{
                    //如果billType=1，就设置billType=2，再来一遍
                    if(billType==1){
                        billType = 2;
                        getJddiBalanceBillList(startDate,endDate,1L, billType,balanceBillList);
                    }
                }
            }
        }
    }

    /**
     * 根据京东到家订单id，查询查询订单计费明细
     * 接口地址:https://openapi.jddj.com/djapi/bill/checkBill（订单号最大个数为50个）
     * @param jddjOrderId
     * @return
     */
    List<OmsJddjOrderBill> getJddjOrderBillList(List<Long> jddjOrderId) throws Exception {
        List<OmsJddjOrderBill> resultBillList = new ArrayList<>();
        List<List<Long>> lists = new ArrayList<>();
        if (jddjOrderId.size() > 50) {
            lists = Lists.partition(jddjOrderId, 50);
        }else{
            lists.add(jddjOrderId);
        }

        for(List<Long> list : lists){
            String timestamp = DateUtils.now();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("orderIds", list);
            JSONObject resultObj = requestJddjHttp(orderBillUrl, jsonObject.toJSONString(), timestamp);
            if (resultObj!=null) {
                if (Objects.equals("0", resultObj.getString("code"))) {
                    JSONArray jsonArray = resultObj.getJSONObject("data").getJSONArray("result");
                    resultBillList.addAll(JSONArray.parseArray(jsonArray.toJSONString(), OmsJddjOrderBill.class));
                }
            }
        }
        return resultBillList;
    }

    void removeOrderIfNoBalanceBill(List<OmsJddjOrderVO> orderVOList, List<OmsJddjBalanceBill> balanceBillList){
        //遍历orderVOList，如果存在订单计费明细，就设置到orderVO对象中；如果找不到订单计费明细，就删除这个orderVO
        Iterator<OmsJddjOrderVO> iterator = orderVOList.iterator();
        while (iterator.hasNext()){
            OmsJddjOrderVO orderVO = iterator.next();
            List<OmsJddjBalanceBill> collect = balanceBillList.stream().filter(q -> Objects.equals(q.getOrderId(), orderVO.getOrderId())).collect(Collectors.toList());
            if(collect.isEmpty()){
                iterator.remove();
            }else{
                orderVO.setBalanceBillList(collect);
            }
        }
    }

    /**
     * 根据京东订单id，如果找不到OrderBill信息，就删除orderVOList中的数据
     */
    /*void removeOrderIfNoBill(List<OmsJddjOrderVO> orderVOList, List<OmsJddjOrderBill> orderBillList){
        //移除订单货款状态不对的
        orderBillList.removeIf(q->q.getGoogsSettlementStatus()!=2 || !Arrays.asList(2,3).contains(q.getMarketSettlementStatus()));

        //遍历orderVOList，如果存在订单计费明细，就设置到orderVO对象中；如果找不到订单计费明细，就删除这个orderVO
        Iterator<OmsJddjOrderVO> iterator = orderVOList.iterator();
        while (iterator.hasNext()){
            OmsJddjOrderVO orderVO = iterator.next();
            List<OmsJddjOrderBill> collect = orderBillList.stream().filter(q -> Objects.equals(q.getOrderId(), orderVO.getOrderId())).collect(Collectors.toList());
            if(collect.isEmpty()){
                iterator.remove();
            }else{
                orderVO.setOrderBillList(collect);
            }
        }
    }*/

    private void convertStoreOrder(OmsJddjOrderVO vo) {
        Long storeId = Long.valueOf(vo.getDeliveryStationNoIsv());
        OmsOrderPage orderPage = thirdOrderHandle.generateStoreOrderWithJddj(vo,storeId);
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderPage, omsOrder);
        stmOrderService.saveMain(omsOrder, orderPage.getOmsOrderItemList(), orderPage.getOmsOrderInvoiceList());
        OmsOrderAddition orderAddition = new OmsOrderAddition();
        orderAddition.setId(omsOrder.getId());
        orderAddition.setProductNames("京东到家");
        orderAddition.setPrintNumber(0);
        stmOrderAdditionService.save(orderAddition);
        List<StmStockVO> stockVOS = thirdOrderHandle.generateStockRecord(orderPage);
        String changeReason = "京东到家销售出库";
        stmStockService.stockInOut(stockVOS, storeId, StockConstant.STOCK_OUT, StockConstant.STOCK_OUT_TYPE_SALE, StockConstant.RECEIPT_TYPE_SALE, vo.getId(), changeReason );
    }

    private void checkJddjOrderWithDb(List<OmsJddjOrderVO> orderVOS) {
        List<Long> orderIds = orderVOS.stream().map(OmsJddjOrderVO::getOrderId).collect(Collectors.toList());
        LambdaQueryWrapper<OmsJddjOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(OmsJddjOrder::getOrderId, orderIds);
        List<OmsJddjOrder> orderList = omsJddjOrderService.list(wrapper);
        List<OmsJddjOrderVO> dbOrderVO = new ArrayList<>();
        orderList.forEach(order->{
            orderVOS.stream().filter(vo->Objects.equals(vo.getOrderId(),order.getOrderId())).forEach(vo->{
                dbOrderVO.add(vo);
            });
        });
        orderVOS.removeAll(dbOrderVO);
    }

    private void getJddjOrderWithPage(String startTime, String endTime, Long pageNo,List<OmsJddjOrderVO> orderVOS) throws Exception {
        String timestamp = DateUtils.now();

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("pageNo", pageNo);
        jsonObject.put("pageSize", pageSize);
        jsonObject.put("orderStartTime_begin", startTime);
        jsonObject.put("orderStartTime_end", endTime);
        jsonObject.put("orderStatus", 90000);

        JSONObject resultObj = requestJddjHttp(orderUrl, jsonObject.toJSONString(), timestamp);
        if (resultObj!=null) {
            if (Objects.equals("0", resultObj.getString("code"))) {
                String encryptData = resultObj.getString("encryptData");
                if(StrUtil.isBlank(encryptData)) {
                    throw new RuntimeException("encryptData为空");
                }
                String key = ApiUtil.getJddjAppSecret().substring(0, 16);
                String iv = ApiUtil.getJddjAppSecret().substring(16, 32);
                String data = AESUtils.decryptAES(encryptData, key, iv);
                JSONObject resultData = JSONObject.parseObject(data).getJSONObject("result");
                if (oConvertUtils.isEmpty(resultData.getJSONArray("resultList"))) return;
                JSONArray jsonArray = resultData.getJSONArray("resultList");
                List<OmsJddjOrderVO> voList = JSONArray.parseArray(jsonArray.toJSONString(), OmsJddjOrderVO.class);
                orderVOS.addAll(voList);
                Integer resPageNo = resultData.getInteger("pageNo");
                Integer resPageSize = resultData.getInteger("pageSize");
                Integer resMaxPageSize = resultData.getInteger("maxPageSize");
                Integer resTotalCount = resultData.getInteger("totalCount");
                if (resPageSize > resMaxPageSize) {
                    resPageSize = resMaxPageSize;
                }
                if (resPageNo * resPageSize < resTotalCount) {
                    getJddjOrderWithPage(startTime,endTime,pageNo + 1, orderVOS);
                }
            }
        }
    }

    JSONObject requestJddjHttp(String url, String paramJson, String timestamp) throws Exception {
        WebRequestDTO webReqeustDTO = new WebRequestDTO();
        webReqeustDTO.setApp_key(ApiUtil.getJddjAppKey());
        webReqeustDTO.setFormat(format);
        webReqeustDTO.setJd_param_json(paramJson);
        webReqeustDTO.setTimestamp(timestamp);
        webReqeustDTO.setToken(ApiUtil.getJddjToken());
        webReqeustDTO.setV(v);

        String sign = SignUtils.getSignByMD5(webReqeustDTO, ApiUtil.getJddjAppSecret());
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("token", ApiUtil.getJddjToken());
        param.put("app_key", ApiUtil.getJddjAppKey());
        param.put("timestamp", timestamp);
        param.put("sign", sign);
        param.put("format", format);
        param.put("v", v);
        param.put("jd_param_json", paramJson);

        String result = HttpUtil.postRequest(url, param);
        log.info("result: {}",result);
        //{"code":"0","msg":"操作成功, UUID[b64fd6d22a494222994ac4455964d091]","data":"{\"msg\":\"成功\",\"result\":\"{\\\"pageNo\\\":1,\\\"pageSize\\\":20,\\\"maxPageSize\\\":100,\\\"totalCount\\\":0,\\\"page\\\":1,\\\"totalPage\\\":0}\",\"code\":\"0\",\"success\":true,\"detail\":null}","success":true}
        if (oConvertUtils.isNotEmpty(result)) {
            return JSON.parseObject(result);
        }
        return null;
    }


    public String generateOrderSn() {
        String date = new SimpleDateFormat("yyyyMMddHH").format(new Date());
        String key = "portal:orderId:" + date;
        long seq = redisUtil.incr(key, 1);
        if (seq == 1L) {
            seq = redisUtil.incr(key, (long) (Math.random() * 500000));
            redisUtil.expire(key, 3600 * 2L);
        }
        return "" + IdUtil.genId("yyMMddHH{s}{s}{s}{s}{s}{r}{s}7", seq, 6);
    }

}
